

-- Copyright (C) 2020 2024 PsycoJaker

-- This file is part of UwU Minetest Mod.

-- UwU Mod is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as
-- published by the Free Software Foundation, either version 3 of the
-- License, or (at your option) any later version.

-- UwU Mod is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU Affero General Public License for more details.

-- You should have received a copy of the GNU Affero General Public License
-- along with UwU Mod.  If not, see <https://www.gnu.org/licenses/>.



local S = core.get_translator(core.get_current_modname())

uwu = {}

uwu.growhappiness = 50

function uwu.timer()
	return math.random(30, 50)
end

function uwu.newpos(pos)
   -- return nearest air node pos or nil
   local up = {x=pos.x, y=pos.y+1, z=pos.z}
   local down = {x=pos.x, y=pos.y-1, z=pos.z}
   local side1 = {x=pos.x+1, y=pos.y, z=pos.z}
   local side2 = {x=pos.x-1, y=pos.y, z=pos.z}
   local side3 = {x=pos.x, y=pos.y, z=pos.z+1}
   local side4 = {x=pos.x, y=pos.y, z=pos.z-1}
   local r = math.random(1, 5)
   if core.get_node(down).name == "air" then
      return down
   elseif r == 1 and core.get_node(side1).name == "air" then
      return side1
   elseif r == 2 and core.get_node(side2).name == "air" then
      return side2
   elseif r == 3 and core.get_node(side3).name == "air" then
      return side3
   elseif r == 4 and core.get_node(side4).name == "air" then
      return side4
   elseif r == 5 and core.get_node(up).name == "air" then
      return up
   else
      return nil
   end
end

function uwu.rotate(pos, param2)
	local r = math.random(0, 3)
	local node = core.get_node(pos)
	param2 = param2 or r
	node.param2 = param2
	core.swap_node(pos, node)
	return true
end

function uwu.walk(pos)
   local oldnode = core.get_node(pos)
   local oldnodemeta = core.get_meta(pos):to_table()
   local newpos = uwu.newpos(pos)
   if newpos then
      core.set_node(newpos, oldnode)
      core.get_meta(newpos):from_table(oldnodemeta)
      core.get_node_timer(newpos):start(uwu.timer())
      core.set_node(pos, {name = "air"})
   end
end

function uwu.particles(pos, happiness, texture)
	local meta = core.get_meta(pos)
	local happiness = happiness or meta:get_int("happiness")
	local texture = texture or "heart.png"
	local amount = 100
	if type(happiness) == "number" and happiness+5 < 100 then
		amount = happiness+5
	end
	core.add_particlespawner({
		amount = amount,
		time = 0.0001,
		minpos = pos,
		maxpos = pos,
		minvel = vector.new(-1,1,-1),
		maxvel = vector.new(1,3,1),
		minexptime = 0.7,
		maxexptime = 1,
		minsize = 1,
		maxsize = 2,
		collisiondetection = false,
		vertical = false,
		texture = texture,
	})
end

function uwu.add_happiness(pos, num, prob)
	-- if prob take happiness 1/prob times
	local meta = core.get_meta(pos)
	local happiness = meta:get_int("happiness")
	local rprob = prob or 1
	local r = math.random(1, rprob)
	if r == 1 and happiness+num >= 0 then
		meta:set_int("happiness", happiness+num)
		if happiness+num <= 0 then
			meta:set_string("infotext", S("UnU block\nHappiness: @1", happiness+num))
		else
			meta:set_string("infotext", S("UwU block\nHappiness: @1", happiness+num))
		end
		uwu.particles(pos, happiness+num)
	end
end

function uwu.burp (pos, prob)
   local rprob = prob or 1
   local r = math.random(1, rprob)
   if r == 1 then
      core.sound_play("burp", {
	 pos = pos,
	 gain = 22,
	 max_hear_distance = 20,
	 pitch = math.random(70,110)/100
      })
   else
      core.sound_play("mcl_hunger_bite", {pos = pos, gain = 0.2})
   end
end

function uwu.say_uwu(pos, prob)
   local rprob = prob or 1
   local r = math.random(1, rprob)
   local nodename = core.get_node(pos).name
   local pitch = 1
   if r == 1 then
      if nodename == "uwu:little" then pitch = 2 end
      core.sound_play("uwu", {
	 pos = pos,
	 gain = 5,
	 pitch = pitch
      })
   end
end

function uwu.on_rightclick(pos, node, clicker, itemstack)
   local itemname = itemstack:get_name()
   local isfood = core.get_item_group(itemname, "food") -- int num
   local energy = core.get_item_group(itemname, "eatable") or 1
   if isfood >= 1 then
      itemstack:take_item()
      uwu.add_happiness(pos, energy)
      uwu.burp(pos, 5)
   end
end

function uwu.grow(pos)
   local nodename = core.get_node(pos).name
   local newpos = uwu.newpos(pos)
   if nodename == "uwu:block" then
      if newpos then
	 core.set_node(newpos, {name = "uwu:little"} )
	 uwu.add_happiness(pos, 1-uwu.growhappiness)
	 uwu.add_happiness(newpos, 1-uwu.growhappiness)
	 core.get_node_timer(newpos):start(uwu.timer())
	 uwu.say_uwu(pos)
      end
   end
   if nodename == "uwu:little" then
      core.set_node(pos, {name = "uwu:block"} )
      uwu.add_happiness(pos, 1-uwu.growhappiness)
      uwu.say_uwu(pos)
   end
end



-- Returns a function that spawns children in a circle around pos.
-- To be used as on_die callback.
-- self: mob reference
-- pos: position of "mother" mob
-- child_mod: Mob to spawn
-- spawn_distance: Spawn distance from "mother" mob
-- eject_speed: Initial speed of child mob away from "mother" mob
function uwu.spawn_children_on_die(child_mob, spawn_distance, eject_speed)
   return function(self, pos)
      local posadd, newpos, dir
      if not eject_speed then
	 eject_speed = 1
      end
      local mndef = minetest.registered_nodes[minetest.get_node(pos).name]
      local mother_stuck = mndef and mndef.walkable
      local angle = math.random(0, math.pi*2)
      local children = {}
      local spawn_count = math.random(2, 4)
      for i = 1, spawn_count do
	 dir = vector.new(math.cos(angle), 0, math.sin(angle))
	 posadd = vector.normalize(dir) * spawn_distance
	 newpos = pos + posadd
	 -- If child would end up in a wall, use position of the "mother", unless
	 -- the "mother" was stuck as well
	 if not mother_stuck then
	    local cndef = minetest.registered_nodes[minetest.get_node(newpos).name]
	    if cndef and cndef.walkable then
	       newpos = pos
	       eject_speed = eject_speed * 0.5
	    end
	 end
	 local mob = minetest.add_entity(newpos, child_mob)
	 if not mother_stuck then
	    mob:set_velocity(dir * eject_speed)
	 end
	 mob:set_yaw(angle - math.pi/2)
	 table.insert(children, mob)
	 angle = angle + (math.pi*2) / spawn_count
      end
      -- If mother was murdered, children attack the killer after 1 second
      if self.state == "attack" then
	 minetest.after(1.0, function(children, enemy)
			   local le
			   for c = 1, #children do
			      le = children[c]:get_luaentity()
			      if le then
				 le.state = "attack"
				 le.attack = enemy
			      end
			   end
	 end, children, self.attack)
      end
   end
end

function uwu.entity_on_pickup(self, itementity)
   local pos = self.pos
   minetest.add_entity(pos, "uwu:uwu_tiny")
end      
